package com.aokser.redisplugin.redis;

import com.aokser.redisplugin.config.BaseConfig;
import com.aokser.redisplugin.exception.RedisPluginException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.util.List;
import java.util.Set;


/**
 * Jedis客户端
 * @version 1.0
 * @author aokser@foxmail.com
 */
@Component
@Lazy(true)
public class JedisClient implements InitializingBean{

    private static Logger log = LoggerFactory.getLogger(JedisClient.class);
    
    @Autowired
    private BaseConfig baseConfig;
    
    private static JedisPool jedisPool = null;
 
    public JedisClient() {
    }
 
    /**
     * 初始化方法
     */
    public void init() throws RedisPluginException {
        if(null == baseConfig.getHost() || 0 == baseConfig.getPort()){
            log.error("请初始化redis配置文件！");
            throw new NullPointerException("Redis配置为空，请检查配置！");
        }
        
        if(jedisPool == null){
            if(StringUtils.isEmpty(baseConfig.getPassword())) {
                jedisPool = new JedisPool(new JedisPoolConfig(), baseConfig.getHost(), 
                        baseConfig.getPort(),  baseConfig.getTimeout());
            } else {
                jedisPool = new JedisPool(new JedisPoolConfig(), baseConfig.getHost(), 
                        baseConfig.getPort(), baseConfig.getTimeout(), 
                        baseConfig.getPassword(), baseConfig.getDataBase());
            }
        }
    }
    
    /**
     * 获取key 对应的string 值,如果key 不存在返回nil
     * @param key 键值
     * @return byte[]
     */
    public byte[] get(byte[] key) {
        byte[] value = null;
        Jedis jedis = jedisPool.getResource();
        try {
            value = jedis.get(key);
        } finally {
            close(jedis);
        }
        return value;
    }
    /**
     * 获取key 对应的string 值,如果key 不存在返回nil
     * @param key 键值
     * @return String
     */
    public String get(String key) {
        String value=null;
        Jedis jedis = jedisPool.getResource();
        try {
            value = jedis.get(key);
        } finally {
            close(jedis);
        }
        return value;
    }
 
    /**
     * 设置key 对应的值为string 类型的value 
     * @param key
     * @param value
     * @return byte[]
     */
    public byte[] set(byte[] key, byte[] value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
        } finally {
            close(jedis);
        }
        return value;
    }
    /**
     * 设置key 对应的值为string 类型的value 
     * @param key
     * @param value
     * @return String
     */
    public String set(String key,String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
        } finally {
            close(jedis);
        }
        return value;
    }
 
    /**
     * 设置key 对应的值为string 类型的value， 并设置超时时长
     * @param key 键值
     * @param value 数据
     * @param expire 超时时长
     * @return byte[]
     */
    public byte[] set(byte[] key, byte[] value, int expire) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } finally {
            close(jedis);
        }
        return value;
    }
    /**
     * 设置key 对应的值为string 类型的value， 并设置超时时长 
     * @param key
     * @param value
     * @param expire
     * @return String
     */
    public String set(String key,String value, int expire) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } finally {
            close(jedis);
        }
        return value;
    }
 
    /**
     * 删除指定key的数据
     * @param key 键值
     */
    public void del(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 删除指定key的数据
     * @param key 键值
     */
    public void del(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } finally {
            close(jedis);
        }
    }
 
    /**
     * 删除当前选择数据库中的所有key
     */
    public void flushDB() {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.flushDB();
        } finally {
            close(jedis);
        }
    }
 
    /**
     * 返回当前数据库中key 的数目
     * @return Long
     */
    public Long dbSize() {
        Long dbSize = 0L;
        Jedis jedis = jedisPool.getResource();
        try {
            dbSize = jedis.dbSize();
        } finally {
            close(jedis);
        }
        return dbSize;
    }
 
    /**
     * 返回当前数据库中key 的数目
     * @param pattern 过滤规则
     * @return Set<byte[]>
     */
    public Set<byte[]> keys(byte[] pattern) {
        Set<byte[]> keys = null;
        Jedis jedis = jedisPool.getResource();
        try {
            keys = jedis.keys(pattern);
        } finally {
            close(jedis);
        }
        return keys;
    }

    /**
     * 返回当前数据库中key 的数目
     * @param pattern 过滤规则
     * @return Set<byte[]>
     */
    public Set<String> keys(String pattern) {
        Set<String> keys = null;
        Jedis jedis = jedisPool.getResource();
        try {
            keys = jedis.keys(pattern);
        } finally {
            close(jedis);
        }
        return keys;
    }
    
    /*
    public void ping() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.ping();
        } catch(JedisConnectionException e) {
            throw new PluginException("Redis服务器连接异常，将导致系统功能无法正常使用，请检查网络或配置信息！");
        } finally {
            close(jedis);
        }
    }
    */
    
    /**
     * 关闭
     * @param jedis
     */
    public void close(Jedis jedis) {
        if(null != jedis) {
            jedis.close();
        }
    }
    
    /**
     * 从头部添加元素
     * @param key 键值
     * @param value 数据
     */
    public void lpush(byte[] key, byte[] value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.lpush(key, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 从头部添加元素
     * @param key 键值
     * @param value 数据
     */
    public void lpush(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.lpush(key, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 从尾部添加元素
     * @param key 键值
     * @param value 数据
     */
    public void rpush(byte[] key, byte[] value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.rpush(key, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 从尾部添加元素
     * @param key 键值
     * @param value 数据
     */
    public void rpush(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.rpush(key, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 从list 的头部删除元素，并返回删除元素
     * @param key 键值
     * @return byte[]
     */
    public byte[] lpop(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.lpop(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 从list 的头部删除元素，并返回删除元素
     * @param key 键值
     * @return String
     */
    public String lpop(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.lpop(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 从list 的尾部删除元素，并返回删除元素
     * @param key 键值
     * @return byte[]
     */
    public byte[] rpop(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.rpop(key);
        } finally {
            close(jedis);
        }
    }

    /**
     * 从list 的尾部删除元素，并返回删除元素
     * @param key 键值
     * @return String
     */
    public String rpop(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.rpop(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回key 对应list 的长度
     * @param key 键值
     * @return Long
     */
    public Long llen(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.llen(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回存储在 key 的列表里指定范围内的元素
     * @param key 键值
     * @param start 起始索引
     * @param end 结束索引
     * @return List<byte[]>
     */
    public List<byte[]> lrange(byte[] key, long start, long end) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.lrange(key, start, end);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回存储在 key 的列表里指定范围内的元素
     * @param key 键值
     * @param start 起始索引
     * @param end 结束索引
     * @return List<byte[]>
     */
    public List<String> lrange(String key, long start, long end) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.lrange(key, start, end);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 向名称为key 的set 中添加元素
     * @param key 键值
     * @param value 数据集
     */
    public void sadd(byte[] key, byte[] ... value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.sadd(key, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 向名称为key 的set 中添加元素
     * @param key 键值
     * @param value 数据集
     */
    public void sadd(String key, String ... value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.sadd(key, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 删除名称为key 的set 中的元素member
     * @param key 键值
     */
    public void srem(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.srem(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回名称为key 的set 的元素个数
     * @param key 键值
     * @return long
     */
    public long scard(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.scard(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回所有成员
     * @param key 键值
     * @return Set<byte[]>
     */
    public Set<byte[]> smembers(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.smembers(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回所有成员
     * @param key 键值
     * @return Set<byte[]>
     */
    public Set<String> smembers(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.smembers(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 设置hash field 为指定值，如果key 不存在，则先创建
     * @param key 键值
     * @param field 字段
     * @param value 数据
     */
    public void hset(byte[] key, byte[] field, byte[] value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.hset(key, field, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 设置hash field 为指定值，如果key 不存在，则先创建
     * @param key 键值
     * @param field 字段
     * @param value 数据
     */
    public void hset(String key, String field, String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.hset(key, field, value);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 获取指定的hash field
     * @param key 键值
     * @param field 字段
     * @return byte[]
     */
    public byte[] hget(byte[] key, byte[] field) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hget(key, field);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 获取指定的hash field
     * @param key 键值
     * @param field 字段
     * @return byte[]
     */
    public String hget(String key, String field) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hget(key, field);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回hash 的所有value
     * @param key 键值
     * @return List<String>
     */
    public List<String> hvals(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hvals(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回hash 的所有value
     * @param key 键值
     * @return List<String>
     */
    public List<byte[]> hvals(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hvals(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回hash 的所有field
     * @param key 键值
     * @return Set<byte[]>
     */
    public Set<byte[]> hkeys(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hkeys(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回hash 的所有field
     * @param key 键值
     * @return Set<String>
     */
    public Set<String> hkeys(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hkeys(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回指定hash 的field 数量
     * @param key 键值
     * @return long
     */
    public long hlen(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hlen(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 返回指定hash 的field 数量
     * @param key 键值
     * @return long
     */
    public long hlen(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hlen(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 删除指定hash 的field
     * @param key 键值
     * @param field 字段
     * @return long
     */
    public long hdel(byte[] key, byte[] field) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hdel(key, field);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 删除指定hash 的field
     * @param key 键值
     * @param field 字段
     * @return long
     */
    public long hdel(String key, String field) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.hdel(key, field);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 发布 
     * @param channel 通道
     * @param message 消息
     */
    public void publish(byte[] channel, byte[] message) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.publish(channel, message);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 发布 
     * @param channel 通道
     * @param message 消息
     */
    public void publish(String channel, String message) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.publish(channel, message);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 生成递增的整数值 
     * @param key 键值
     * @return long
     */
    public long incr(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.incr(key);
        } finally {
            close(jedis);
        }
    }
    
    /**
     * 生成递增的整数值 
     * @param key 键值
     * @return long
     */
    public long incr(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.incr(key);
        } finally {
            close(jedis);
        }
    }
    
    public String type(String key) {
    	Jedis jedis = jedisPool.getResource();
        try {
            return jedis.type(key);
        } finally {
            close(jedis);
        }
    }

    /**
     * 订阅
     * @param channel
     */
    public void subscribe(RedisPluginSubscribe redisPluginSubscribe, String channel) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.subscribe(redisPluginSubscribe, channel);
        } catch (JedisConnectionException e) {
            if(jedis != null) {
                jedis.close();
            }
            subscribe(redisPluginSubscribe, channel);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        init();
    }
}
